/**
 * Created by Administrator on 2015/6/10.
 */
import com.mysql.jdbc.*;
import redis.clients.jedis.*;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.sql.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class RedisDataTool {
    public static void main(String[] args) throws IOException, SQLException, ClassNotFoundException {

        HashMap hm = getArgsMap(args);
        //printHashMap(hm);
        checkArgs(hm);
        //提交到sqlite的数量
        int commit_num=100;

        Jedis jedis=new Jedis(hm.get("h").toString(),Integer.parseInt(hm.get("p").toString()));
        if(!hm.get("a").equals(""))
        {
            jedis.auth(hm.get("a").toString());
        }
        jedis.select(Integer.parseInt(hm.get("n").toString())) ;

        if(hm.get("type").equals("dump"))
        {
            setRedisToDb(jedis,hm.get("d").toString()+"/"+hm.get("n").toString()+".db",commit_num);
        }
        if(hm.get("type").equals("load")){

            restoreFromdb(jedis,hm.get("d").toString());
        }


    }



    public  static void checkArgs(HashMap hm) throws IOException {
        //是否打印help
        if(hm.get("help")=="1" ||hm.size()==0)
        {
            printUsage();
            System.exit(0);
        }
        //type检查
        if(hm.get("type")==null)
        {
            hm.put("type","dump");
        }
//        System.out.println(hm.get("type"));
//        System.out.println(hm.get("type").equals("dump"));
        if(!hm.get("type").equals("dump") && !hm.get("type").equals("load"))
        {
            System.out.println("type 参数必须为（dump 或 load)");
            System.exit(0);
        }
        //host检查
        if(hm.get("h")==null)
        {
            hm.put("h","localhost");
        }
        if(!hm.get("h").toString().matches("[A-Za-z0-9\\.]+"))
        {
            System.out.println("h 参数异常，可用 -help查看用法");
            System.exit(0);
        }
        //port检查
        if(hm.get("p")==null)
        {
            hm.put("p","6379");
        }
        if(!hm.get("p").toString().matches("[0-9]+")){
            System.out.println("p 参数异常，可用 -help查看用法");
            System.exit(0);
        }
        //pass检查
        if(hm.get("a")==null)
        {
            hm.put("a","");
        }
        //db检查
        if(hm.get("n")==null)
        {
            hm.put("n","0");
        }
        if(!hm.get("n").toString().matches("[0-9]+")){
            System.out.println("n 参数异常，可用 -help查看用法");
            System.exit(0);
        }
        //目录检查 （type=dump目录不存在自动创建，type=load文件不存在提示并退出）
        if(hm.get("d")==null)
        {
            if(hm.get("type").equals("dump")) {
                hm.put("d", ".");
            }
            if(hm.get("type").equals("load")) {
                hm.put("d", "./0.db");
            }
        }

        if(hm.get("type").equals("dump")) {
            //如果目录不存在，就创建之
            File file=new File(hm.get("d").toString());
            if(!file.exists() && !file.mkdir())
            {
                System.out.println("检查参数 -d ,--help查看帮助");
                System.exit(0);
            }
        }
        if(hm.get("type").equals("load")) {
            //如果文件不存在，就退出
            File file =new File(hm.get("d").toString());
            if(!file.isFile())
            {
                System.out.println("备份文件不存在,检查参数 -d ,--help查看帮助");
                System.exit(0);
            }
        }



    }
    public  static  HashMap getArgsMap(String[] args)
    {
        HashMap<String,String > hm=new HashMap();
        for(int i=0;i<args.length;i++)
        {
            //帮助命令的处理
            if(args[i].toLowerCase().equals("-help")||args[i].toLowerCase().equals("--help"))
            {
                hm.put("help","1");
            }else {
                String key = args[i].substring(args[i].indexOf("-") + 1, args[i].indexOf("=")).toLowerCase();
                String val = args[i].substring(args[i].indexOf("=") + 1).toLowerCase();
                hm.put(key, val);
            }
        }
        return hm;

    }
    public static  void printUsage()
    {
        String usage="使用方法：\n" +
                "java RedisDataTool -type=dump -h=192.168.0.123 -p=6380 -a=123 -n=1 -d=.\n" +
                "\n" +
                "--help 打印帮助信息\n" +
                "-type  操作类型:dump导出 load恢复. 默认为dump\n" +
                "-h     连接redis实例的ip。默认为localhost\n" +
                "-p     连接redis实例的端口。默认为6379\n" +
                "-a     redis认证密码。默认为空\n" +
                "-n     选择redis的db位置。默认为0\n" +
                "-d     如果-type=dump,表示导出的目录 -d=。表示当前目录，默认当前目录\n" +
                "       备份文件规则 0.db、1.db、2.db...15.db\n" +
                "       如果-type=load,表示导入的备份文件 -d=./0.db 默认当前目录的0.db";
        System.out.println(usage);
    }
    public static void printHashMap(HashMap hm)
    {
        Iterator it = hm.entrySet().iterator();
        while (it.hasNext())
        {
            Map.Entry entry = (Map.Entry)it.next();
            Object key=entry.getKey();
            Object val=entry.getValue();

            System.out.println(key.toString()+" : "+val.toString());

        }
    }
    public static void readFileByLines(String fileName) {
        File file = new File(fileName);
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            int line = 1;
            // 一次读入一行，直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                // 显示行号
                System.out.println("line " + line + ": " + tempString);
                line++;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
    }


    public static String GetLineValue(String fileName) {
        File file = new File(fileName);
        BufferedReader reader = null;
        String str = null;
        try {
            //System.out.println("以行为单位读取文件内容，一次读一整行：");
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            int line = 1;
            // 一次读入一行，直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                // 显示行号
                str = tempString;
                break;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }

        return str;
    }

    public static void printHexString(byte[] b) {
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            System.out.print(hex.toUpperCase());
        }

    }

    public static char[] getChars(byte[] bytes) {
        Charset cs = Charset.forName("UTF-8");
        ByteBuffer bb = ByteBuffer.allocate(bytes.length);
        bb.put(bytes);
        bb.flip();
        CharBuffer cb = cs.decode(bb);

        return cb.array();
    }

    public static void setRedisDumpToFile(Jedis jedis,String key,String dir) throws IOException
    {
        //获取dump值
        byte[] b=jedis.dump(key);
        createFile(dir+key,b);

    }
    public static void setRedisDumpToDir(Jedis jedis,String dir) throws IOException
    {
        String dirname=dir;

        //dump所有的key到文件夹tmp
        Set  keys=jedis.keys("*");
        Iterator i=keys.iterator();
        while (i.hasNext() )
        {
            //System.out.println(i.next());
            setRedisDumpToFile(jedis,i.next().toString(),dirname);
        }
    }

    public  static void setRedisKeyToDb(Jedis jedis,String key,String dbfile) throws IOException, ClassNotFoundException, SQLException {
        //获取dump值
        byte[] b=jedis.dump(key);
        Class.forName("org.sqlite.JDBC");
        String driverName="jdbc:sqlite:"+dbfile;
        java.sql.Connection conn=DriverManager.getConnection(driverName);
        PreparedStatement ps=conn.prepareStatement("insert into redis_dump values (?,?);");
        ps.setInt(1,1);
        ps.setBytes(2,b);
        ps.execute();
        conn.close();


    }
    public  static void setRedisToDb(Jedis jedis, String dbfile, int commit_num) throws IOException, ClassNotFoundException, SQLException {
        Class.forName("org.sqlite.JDBC");
        String driverName="jdbc:sqlite:"+dbfile;
        String createSql="create table  redis_dump(key varchar(1000),value blob);";
        String trunSql="drop  table if  exists redis_dump;";

        java.sql.Connection conn=DriverManager.getConnection(driverName);
        Statement stat=conn.createStatement();
        //删除表
        stat.executeUpdate(trunSql);
        //如果没有表，进行创建
        stat.executeUpdate(createSql);


        stat.close();

        conn.setAutoCommit(false);
        PreparedStatement ps=conn.prepareStatement("insert into redis_dump values (?,?);");

        //插入计数
        int count=0;
        //插入dump的数据
        Set s=jedis.keys("*");
        Iterator i=s.iterator();
        while(i.hasNext()){
            String key=i.next().toString();
            ps.setString(1, key);
            ps.setBytes(2,jedis.dump(key));
            ps.addBatch();
            //按commit_num提交
            if(count==commit_num) {
                ps.executeBatch();
                conn.commit();
                count=0;
            }
        }
        ps.executeBatch();
        conn.commit();

        ps.close();
        //关闭sqlite连接
        conn.close();


    }

    private static void restoreFromdb(Jedis jedis, String dbfile) throws ClassNotFoundException, SQLException {

        Class.forName("org.sqlite.JDBC");
        String driverName="jdbc:sqlite:"+dbfile;
        //System.out.println(driverName);
        java.sql.Connection conn=DriverManager.getConnection(driverName);
        Statement stat=conn.createStatement();
        ResultSet rs=stat.executeQuery("select * from redis_dump");

        while(rs.next()){

           jedis.restore(rs.getString(1),0,rs.getBytes(2));
        }

        rs.close();
        stat.close();
        //关闭sqlite连接
        conn.close();
    }

    public  static void restoreKeyFromdb(Jedis jedis,String keyfrom,String keyto,String dbfile)
    {

    }



    public  static void restoreFromKeyFile(Jedis jedis,String key,String filename) throws IOException
    {
        byte[] b= getContent(filename);
        jedis.restore(key,0,b);

    }
    public  static void restoreFromDir(Jedis jedis,String path) throws IOException
    {
        //列出文件名
        File file=new File(path);
        File[] tempList=file.listFiles();
        for (int i = 0; i < tempList.length; i++) {
            if (tempList[i].isFile()) {
                restoreFromKeyFile(jedis,tempList[i].getName(),path+tempList[i].getName());
            }
            if (tempList[i].isDirectory()) {
                //System.out.println(tempList[i].getName());
            }
        }

    }
    //将byte数组写入文件
    public static void createFile(String path, byte[] content) throws IOException {

        FileOutputStream fos = new FileOutputStream(path);

        fos.write(content);
        fos.close();
    }
    //读取文件到byte数组
    public static byte[] getContent(String filePath) throws IOException
    {
        FileInputStream in=new FileInputStream(filePath);

        ByteArrayOutputStream out=new ByteArrayOutputStream(1024);

        //System.out.println("bytes available:"+in.available());

        byte[] temp=new byte[1024];

        int size=0;

        while((size=in.read(temp))!=-1)
        {
            out.write(temp,0,size);
        }

        in.close();

        byte[] bytes=out.toByteArray();
        //System.out.println("bytes size got is:"+bytes.length);

        return bytes;
    }




}
